(* 
  CS520 Final Project
  William Blair
  
  A test 
*)

staload "generator.sats"
staload "random.sats"
staload "container.sats"

staload "random.dats"

dynload "random.dats"

(* Required Libraries *)
staload "contrib/jansson/SATS/jansson.sats"
staload "contrib/gsl/SATS/gsl_statistics.sats"

staload "libats/SATS/parworkshop.sats"
staload "libats/DATS/parworkshop.dats"

staload "prelude/SATS/array.sats"
staload "prelude/DATS/array.dats"

assume label = string
assume distribution = my_distribution
assume input = JSONptr

(* A task is to generate some random numbers according to a distribution. *)
extern
fun generate_random_numbers{l:addr} (
  ws: !WORKSHOPptr(label,l),
  dist: &label >> label?
  ) : int

(* Save all the probability distributions. *)
extern
fun save_tests{l:agz}{n,n1,i:nat | i < n1} (
  ind: int i,
  max: int n1,
  tests: !JSONptr(l,n)
  ) : void

implement
generate_random_numbers{l}(ws,dist) = 
  let 
    fun aux{n:nat}(
      dist:label, 
      cnt:int n
    ) : list(double,n) = 
      if cnt = 0 then list_nil()
      else list_cons(distribution_next_number(dist),aux(dist,cnt - 1))
  #define N 100000
  val list = aux(dist,N)
  val (pfr, pf | results) = array_ptr_alloc_tsz{double}(N,sizeof<double>)
  val () = array_ptr_initialize_lst<double>(!results,list)
  val mean = gsl_stats_mean(!results,1,N)
  val variance = gsl_stats_variance(!results,1,N)
  val sd = gsl_stats_sd(!results,1,N)
  val skew = gsl_stats_skew(!results,1,N)
  val kurtosis = gsl_stats_kurtosis(!results,1,N)
  val () = printf("RNG %s:\nmean:%lf\nvariance:%lf\n:sd:%lf\nskew:%lf\nkurtosis:%lf\n",@(dist,mean,variance,sd,skew,kurtosis))
  val () = array_ptr_free(pfr,pf | results)
  in 0 end
  
implement 
save_tests{l}{n,n1,i}(ind,max,tests) = let
  val (pfe | t) = json_array_get(tests,ind)
  val dist = distribution_parse(t)
  val () = distribution_save(dist)
  prval () = minus_addback(pfe,t | tests)
  in if ind = max - 1 then ((*done*)) else save_tests(ind+1,max,tests) end

implement main () = let
  (* Initiate the environment. *)
  val () = random_setup()
  (* Declare our testing random number generators. *)
  var test:string = "[{\"name\":\"1\",\"type\":\"exponential\",\"lambda\":100.0},{\"name\":\"2\",\"type\":\"normal\",\"mean\":25.0,\"std\":5.0},{\"name\":\"3\",\"type\":\"uniform\",\"min\":0.0,\"max\":10.0},{\"name\":\"4\",\"type\":\"constant\",\"value\":10.0}]"
  var e: json_error_t?
  val tests = json_loads(test,0,e)
  val () = assert_errmsg(JSONptr_isnot_null tests, "Invalid Json given.")
  val size = json_array_size(tests)
  val () = assert_errmsg(size > 0, "No tests given.")
  val () = save_tests(0,size,tests)
  val ws = workshop_make<label>(1,generate_random_numbers)
  (* Add some workers. *)
  val _ = workshop_add_nworker(ws,4)
  val () = workshop_insert_work(ws,"1")
  val () = workshop_insert_work(ws,"2")
  val () = workshop_insert_work(ws,"3")
  val () = workshop_insert_work(ws,"4")
  (* Cleanup *)
  val () = workshop_wait_quit_all(ws)
  val () = json_decref(tests)
  val () = workshop_free(ws)
  in end